package com.feature50.clarity;

import com.feature50.clarity.binding.ClarityBindingContext;
import com.feature50.clarity.formui.FormUI;
import com.feature50.clarity.formui.FormUIFactory;
import com.feature50.clarity.misc.ClarityProgressMonitor;
import com.feature50.util.SwingUtils;
import com.jgoodies.forms.factories.Borders;

import javax.beans.binding.BindingContext;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.border.Border;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.Window;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

public abstract class Form {
    protected FormContainer formContainer;

    protected JComponent formComponent;

    protected FormUI formUI;

    protected ClarityBindingContext bindingContext;

    private boolean initialized = false;

    protected boolean disposed = false;

    // METHODS DESIGNED TO BE OVERRIDDEN

    protected JComponent createFormComponent() throws FormException {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(1, 1));
        return panel;
    }

    protected void createUI(Container container) throws FormException {}

    protected void createActions() throws FormException {}

    protected void getData(ClarityProgressMonitor monitor) throws FormException {}

    protected void configureComponents(Container container) throws FormException{}

    protected void createBindings(BindingContext ctx) throws FormException {}

    protected void addListeners(Container container) throws FormException {}

    protected void activate() throws FormException {}

    protected void passivate(PassivateDirection direction) throws FormPassivationException {}

    protected void postDisplay() throws FormException {}

    protected Object getDataInBackground(ClarityProgressMonitor monitor) throws FormException { return null; }

    protected void backgroundDataRetrieved(Container container, Object data) throws FormException {}

    protected void dispose() {}

    protected JButton getDefaultButton() { return null; }

    public String getTitle() { return ""; }

    protected JComponent getDefaultFocusComponent() { return null; }

    protected boolean isPackLayoutOnDisplay() {
        return false;
    }

    protected Border getBorder() {
        return Borders.DLU4_BORDER;
    }

    public String[] getStylesheetNames() { return null; }

    public String toString() {
        return getClass().getName();
    }

    // METHODS DESIGNED TO BE INVOKED DIRECTLY

    public final FormContainer getFormContainer() {
        return formContainer;
    }

    public final JComponent getFormComponent() {
        return formComponent;
    }

    protected final void loadFormUI(String formName) throws FormException {
        formUI = FormUIFactory.getInstance().getFormUI(formName);
        formComponent.add(formUI.getRootComponent());
    }

    public final Window getWindow() {
        return getFormContainer().getWindow();
    }

    public final JComponent $(String name) {
        return getComponentByName(name);
    }

    public final JComponent[] $s(String... names) {
        List<JComponent> components = new ArrayList<JComponent>();

        for (int i = 0; i < names.length; i++) {
            JComponent c = getComponentByName(names[i]);
            if (c != null) components.add(c);
        }

        return components.toArray(new JComponent[components.size()]);
    }

    public final JComponent[] $$(String selector) {
        return SwingUtils.parseSelector(selector, SwingUtils.getAllJComponents(formComponent));
    }

    public final JComponent getComponentByName(String name) {
        JComponent result = null;
        if (formUI != null) result = formUI.getComponent(name);
        if (result == null) result = SwingUtils.getComponentByName(formComponent, name);
        return result;
    }

    public final JComponent[] getComponentsByPattern(Pattern pattern) {
        return SwingUtils.getComponentsByPattern(getFormComponent(), pattern);
    }

    public final Object get(Object key) {
        return formContainer.get(key);
    }

    public final Object put(Object key, Object value) {
        return formContainer.put(key, value);
    }

    public final void updateBoundComponents() {
        bindingContext.updateComponents();
    }

    // THESE METHODS CAN BE OVERRIDDEN MUST SUBCLASSES MUST INVOKE SUPER.*;

    public boolean isInitialized() {
        return initialized;
    }

    void setInitialized(boolean initialized) {
        this.initialized = initialized;
    }
}